package com.cskaoyan.javase.oop2._1extends._9override;

/**
 * 方法的覆盖/方法的重写
 * 首先父子类中的成员方法,是允许同名的,这时创建子类对象,再来调用同名方法,结果是什么呢?
 * 那么我们直接创建子类对象，使用子类引用接收。调用同名方法，会发现访问的结果是子类中方法的行为，那么父类中的那个同名成员方法去哪了呢？还能够访问吗？
 * 首先它肯定是存在的，方法不过是方法区的二进制指令合集罢了，类加载时期，装载进方法区，不会物理消失。
 * 方法的覆盖/方法的重写,只是因为"对象名点成员方法"的访问机制,导致方法看起来被覆盖,但这个覆盖不是物理意义上的覆盖
 *      我们仍然可以在子类成员方法中使用"super点"去访问父类的同名成员方法(受访问权限限制)
 *
 * 接下来,重点,研究"对象名点成员方法"调用机制,仍然从两个角度:
 *        1.访问范围,能够访问到哪些成员方法
 *        2.方法调用的结果.
 *
 * 当然既然是对象名点访问成员方法,那么创建对象,目前有三种形式:
 *      1.创建子类对象,用子类引用接收
 *      2.创建父类对象,用父类引用接收
 *      3.创建子类对象,但是用父类引用接收
 *
 * 首先研究访问范围:
 *      这里的机制和对象名点访问成员变量是一模一样的
 *      根据引用的数据类型来决定
 *      同时可以找父类,但是不能找子类
 *
 * 重点研究方法调用的结果:
 *      1.创建子类对象,用子类引用接收
 *          子类中实现
 *      2.创建父类对象,用父类引用接收
 *          父类中实现
 *      3.创建子类对象,但是用父类引用接收
 *          子类中实现
 * 以上说明,对象名点成员方法的调用结果,是根据对象的具体类型来决定的.
 *      对于成员方法的调用而言,在代码的运行期间,JVM会自动根据对象的具体类型,去找相应的方法指令,所以成员方法的调用结果是根据对象的具体类型来决定的,和引用无关.
 *
 * 以上总结,对象名点成员方法的访问,访问范围看引用,访问结果看对象,尤其是父子类中存在同名成员方法时,如果对象是子类对象,那么就体现子类的行为,而不是父类.
 *
 * 父子类中出现同名成员方法,它是一种特殊的语法,称之为"方法的重写/覆盖"(override)
 *
 *
 * @since 16:39
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*Son s = new Son();
        s.test();
        s.invokeFatherTest();
        s.invokeFatherTestBySuper();*/

        /*
        // 研究对象名成员方法的访问范围
        Father f = new Father();
        f.test();
        f.testFather();
        Son s = new Son();
        s.testFather();
        s.test();
        s.testSon();
        Father fs = new Son();
        // (fs).testSon();
        */

        // 研究对象名点成员方法的调用结果
        Father f = new Father();
        f.test();
        Son s = new Son();
        s.test();
        Father fs = new Son();
        fs.testFather();
        fs.test();
    }
}

class Father {

    public void test() {
        System.out.println("father");
    }

    /*public void invokeFatherTest(){
        test();
    }*/

    public void testFather() {
        System.out.println("father only");
    }
}

class Son extends Father {
    public void test() {
        System.out.println("son");
    }

    /*public void invokeFatherTestBySuper(){
        super.test();
    }*/

    public void testSon() {
        System.out.println("son only");
    }
}